#include "user_event_handler.h"	
#include "DispatchMsgService.h"
#include "sqlconnection.h"
#include "iniconfig.h"
#include "user_service.h"

#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
#include <unistd.h>

UserEventHandler::UserEventHandler() : iEventHandler("UserEventHandler") {
	//实现订阅事件的处理
	DispatchMsgService::getInstance()->subscribe(EEVENTID_GET_MOBLIE_CODE_REQ, this);
	DispatchMsgService::getInstance()->subscribe(EEVENTID_LOGIN_REQ, this);
	DispatchMsgService::getInstance()->subscribe(EEVENTID_RECHARGE_REQ, this);
	thread_mutex_create(&pm_);
}

UserEventHandler::~UserEventHandler(){
	DispatchMsgService::getInstance()->unsubscribe(EEVENTID_GET_MOBLIE_CODE_REQ, this);
	DispatchMsgService::getInstance()->unsubscribe(EEVENTID_LOGIN_REQ, this);
	DispatchMsgService::getInstance()->subscribe(EEVENTID_RECHARGE_REQ, this);
	thread_mutex_destroy(&pm_);
}

iEvent* UserEventHandler::handle(const iEvent* ev) {
	if (ev == NULL) {
		//LOG_ERROR("input ev is NULL")'
		printf("input ev is NULL");
	}

	u32 eid = ev->get_eid();

	if (eid == EEVENTID_GET_MOBLIE_CODE_REQ) {
		return handle_mobile_code_req((MobileCodeReqEv*)ev);
	}
	else if (eid == EEVENTID_LOGIN_REQ) {
		return handle_login_req((LoginReqEv*) ev);
	}
	else if (eid == EEVENTID_RECHARGE_REQ) {
		return handle_recharge_req((RechargeReqEv*)ev);
	}
	else if (eid == EEVENTID_GET_ACCOUNT_BALANCE_REQ)
	{
		//return handle_get_account_balance_req((GetAccountBalanceEv*) ev);
	}
	else if (eid == EEVENTID_LIST_ACCOUNT_RECORDS_REQ)
	{
		//return handle_list_account_records_req((ListAccountRecordsReqEv*) ev);
	}

	return NULL;
}

MobileCodeRspEv* UserEventHandler::handle_mobile_code_req(MobileCodeReqEv* ev) {
	
	i32 icode = 0;
	mobile_ = ev->get_mobile();
	//LOC_DEBUG("try to get mobile phone %s validate code.", mobile.c_str());
	LOG_DEBUG("try to get mobile phone %s validate code.\n", mobile_.c_str());
	
	icode = code_gen();
	thread_mutex_lock(&pm_);
	m2c_[mobile_] = icode;
	thread_mutex_unlock(&pm_);
	printf("mobile: %s, code: %d\n", mobile_.c_str(), icode);

	// LOG_DEBUG("send sms_success");
	return new MobileCodeRspEv(200, icode);
}

LoginRspEv* UserEventHandler::handle_login_req(LoginReqEv* ev)
{
	LoginRspEv* loginEv = nullptr;
	std::string mobile = ev->get_mobile();
	i32 code = ev->get_code();
	LOG_DEBUG("try to handle login ev, mobile phone %s , code = %d", mobile_.c_str(), code);
	thread_mutex_lock(&pm_);

	auto iter = m2c_.find(mobile);

	if(iter != m2c_.end() && code != iter->second || iter == m2c_.end())
	{
		LOG_ERROR("mobile phone %s login failed, code is not match, code = %d, expect = %d", mobile.c_str(), code, iter->second);
		loginEv =  new LoginRspEv(ERRC_INVALID_DATA);
	}
	thread_mutex_unlock(&pm_);

	if(loginEv) return loginEv;

	//如果验证成功，则要判断用户在数据库是否存在， 不存在则插入用户记录
	std::shared_ptr<MysqlConnection> mysqlconn = std::make_shared<MysqlConnection>();

	st_env_config config_args = Iniconfig::getInstance()->getconfig();
	if (!mysqlconn->Init(config_args.db_ip.c_str(), config_args.db_port, config_args.db_user.c_str(),
		config_args.db_pwd.c_str(), config_args.db_name.c_str())) {
		LOG_ERROR("UserEventHandler::handle_login_req--init mysql is failed . exit!");
		return new LoginRspEv(ERRC_PROCCESS_FALIED);
	}

	UserService us(mysqlconn);
	bool result = false;

	if (!us.exit(mobile))
	{
		LOG_DEBUG("userhandle: noexit mobile phone %s ", mobile_.c_str());
		result = us.insert(mobile);
		if (!result)
		{
			LOG_ERROR("insert user (%s) failed, user is already exist.", mobile.c_str());
			return new LoginRspEv(ERRC_PROCCESS_FALIED);
		}
	}

	LOG_DEBUG("login success, mobile phone %s ", mobile_.c_str());
	return new LoginRspEv(ERRC_SUCCESS);
}

RechargeRspEv* UserEventHandler::handle_recharge_req(RechargeReqEv* ev)
{
	std::string mobile = ev->get_mobile();
	i32 amount = ev->get_amount();
	LOG_DEBUG("try to handle recharge ev, mobile phone %s , amount = %d", mobile.c_str(), amount);

	std::shared_ptr<MysqlConnection> mysqlconn = std::make_shared<MysqlConnection>();

	st_env_config config_args = Iniconfig::getInstance()->getconfig();
	if (!mysqlconn->Init(config_args.db_ip.c_str(), config_args.db_port, config_args.db_user.c_str(),
		config_args.db_pwd.c_str(), config_args.db_name.c_str())) {
		LOG_ERROR("UserEventHandler::handle_recharge_req--init mysql is failed . exit!");
		return new RechargeRspEv(ERRC_PROCCESS_FALIED,0);
	}

	UserService us(mysqlconn);

	if (!us.exit(mobile)) {
		LOG_ERROR("recharge user (%s) not exist.", mobile.c_str());
		return new RechargeRspEv(ERRC_USER_NOT_EXIST,0);
	
	}
	i32 result = us.recharge(mobile, amount);

	if (result == -1) {
		LOG_ERROR("recharge user (%s) failed.", mobile.c_str());
		return new RechargeRspEv(ERRC_PROCCESS_FALIED,0);
	}

	return new RechargeRspEv(ERRC_SUCCESS, result);
}

i32 UserEventHandler::code_gen()
{
	i32 code = 0;
	srand((unsigned int)time(NULL));

	code = (unsigned int)(rand() % (999999 - 100000) + 100000);

	return code;
}